package benchmarks.tpch.mongo.queries;

import api.Configuration;
import api.connection.ConnectionMongo;
import api.connection.DBConnection;
import api.result.Result;
import com.mongodb.*;
import com.mongodb.client.AggregateIterable;
import com.mongodb.client.MongoCursor;
import com.mongodb.client.MongoDatabase;
import org.bson.BsonDocument;
import org.bson.Document;
import org.bson.conversions.Bson;

import java.util.ArrayList;
import java.util.Date;
import java.util.regex.Pattern;

public class Q8Mongo extends GenericQueryMongo {
    public static final String queryName = "Q8";

    public Q8Mongo(){
        super.queryName = queryName;
    }

    private static String matchStringQuery = "{ $match : { $and : [ " +
            "{\"order.customer.nation.region.name\" : { $regex : '^AMERICA'}}, " +
            "{\"partsupp.part.type\" : \"ECONOMY ANODIZED STEEL\" }, " +
            "{\"order.orderdate\" : { \"$gte\" : new Date(1995, 0, 1), \"$lt\" : new Date(1996, 11, 31) } } " +
            "]}}";

    private static String projectStringQuery = "{ $project : { " +
            "\"_id\" : 0, " +
            "\"o_year\" : {$year : \"$order.orderdate\"}, " +
            "\"volume\" : {$multiply : [\"$extendedprice\", {$subtract : [1, \"$discount\"] }] }, " +
            "\"nation\" : \"$partsupp.supplier.nation.name\" " +
            "}\n" +
            "}";

    private static String groupStringQuery = "{ $group : { " +
            "_id : \"$o_year\", " +
            "total : { $sum : \"$volume\" }, " +
            "mkt_sum : { $sum : { " +
            "$cond : { if : { $eq : [\"$nation\", \"BRAZIL\"]}, then : \"$volume\", else : 0 }" +
                "}} " +
            "}}";

    private static String finalProjectStringQuery = "{ $project : { " +
            "\"_id\" : 0, " +
            "\"o_year\" : \"$_id\", " +
            "\"mkt_share\" : {$divide : [\"$mkt_sum\", \"$total\"]}" +
            "}}";

    public Result run(DBConnection dbConnection) {
        ConnectionMongo connectionMongo = (ConnectionMongo)dbConnection;
        MongoClient mongoClient = connectionMongo.makeConnection();
        MongoDatabase database = mongoClient.getDatabase("tpch");
        BsonDocument matchBsonQuery = BsonDocument.parse(matchStringQuery);
        BsonDocument projectBsonQuery = BsonDocument.parse(projectStringQuery);
        BsonDocument groupBsonQuery = BsonDocument.parse(groupStringQuery);
        BsonDocument finalProjectBsonQuery = BsonDocument.parse(finalProjectStringQuery);
        ArrayList<Bson> aggregateQuery = new ArrayList<>();
        aggregateQuery.add(matchBsonQuery);
        aggregateQuery.add(projectBsonQuery);
        aggregateQuery.add(groupBsonQuery);
        aggregateQuery.add(finalProjectBsonQuery);
        AggregateIterable<Document> result  = database.getCollection("deals").aggregate(aggregateQuery);
        MongoCursor<Document> iterator = result.iterator();
        BasicDBList results = new BasicDBList();
        while (iterator.hasNext()) {
            results.add(iterator.next());
        }

        return null;
    }

//    public Result run(DBConnection dbConnection){
//        String regionName = "AMERICA";
//        String nationName = "BRAZIL";
//        MongoClient mongoClient = (MongoClient)dbConnection.makeConnection();
//        DB db = mongoClient.getDB("tpch");
//        DBCollection collection = db.getCollection("deals");
//        Date start = new Date(95, 0, 1);
//        Date end = new Date(96, 11, 31);
//
//        BasicDBObject match = new BasicDBObject();
//        Pattern america = Pattern.compile("^" + regionName);
//        BasicDBObject dateRange = new BasicDBObject();
//        dateRange.append("$gte", start);
//        dateRange.append("$lt", end);
//        match.append("order.customer.nation.region.name", new BasicDBObject("$regex", america));
//        match.append("partsupp.part.type", "ECONOMY ANODIZED STEEL");
//        match.append("order.orderdate", dateRange);
//
//        BasicDBObject project = new BasicDBObject();
//        BasicDBObject[] str = new BasicDBObject[2];
//        str[0] = new BasicDBObject();
//        str[1] = new BasicDBObject();
//        Object[] str1 = new Object[2];
//        str1[0] = "$extendedprice";
//        str1[1] = 0;
//        Object[] str2 = new Object[2];
//        str2[0] = 1;
//        str2[1] = "$discount";
//        str[0].append("$subtract", str1);
//        str[1].append("$subtract", str2);
//        project.append("_id", 0)
//                .append("o_year", new BasicDBObject("$year", "$order.orderdate"))
//                .append("volume", new BasicDBObject("$multiply", str))
//                .append("nation", "$partsupp.supplier.nation.name");
//
//        DBCollection tmp = db.getCollection("tmp");
//        tmp.drop();
//        AggregationOutput output = collection.aggregate(new BasicDBObject("$match", match), new BasicDBObject("$project", project));
//        Iterable<DBObject> list = output.results();
//        for(DBObject dbObject:list){
//            tmp.insert(dbObject);
//        }
//
//
//        String reduce = "function(doc, out){" +
//                "out.o_year = doc.o_year;" +
//                "out.total_sum += doc.volume;" +
//                "if(doc.nation == \"" + nationName + "\"){" +
//                "out.mkt_share += doc.volume;" +
//                "}" +
//                "};";
//
//        String finalize = "function(out){" +
//                "out.mkt_share = out.mkt_share / out.total_sum;" +
//                "delete out.total_sum;" +
//                "};";
//
//        BasicDBObject key =new BasicDBObject("o_year", true);
//
//        BasicDBObject initial = new BasicDBObject();
//        initial.append("total_sum", 0).append("mkt_share", 0);
//        BasicDBList groupList = (BasicDBList)tmp.group(key, null, initial, reduce, finalize);
//       /* System.out.println("Successfully group " + groupList.size());
//        if(groupList != null && groupList.size() > 0){
//            for( int i = 0; i < groupList.size(); i++){
//                BasicDBObject format = (BasicDBObject)groupList.get(i);
//                System.out.println("The answer is: " + format.toString());
//            }
//        }
//        else{
//            System.out.println("none");
//        }*/
//        return null;
//    }
    private static class TestQ8{
        public static void main(String[] args){
            Configuration config = new Configuration();
            config.setBenchmark("tpch");
            config.setDb_username("root");
            config.setDb_password("123456");
            Q8Mongo q8Mongo = new Q8Mongo();
            DBConnection dbConnection =new ConnectionMongo(config);
            q8Mongo.run(dbConnection);
        }
    }
}